#define WIN32_LEAN_AND_MEAN #include <windows.h> #include <stdio.h>
#import "XceedZip.dll" named_guids no_namespace
template< class DataType > static void PrintByteArrayVariant( VARIANT * variant ); static void PrintVariantAsString( VARIANT * variant ); static void PrintVariantAsUnicodeString( VARIANT * variant );
static void StringExample( IXceedCompressionPtr & compression, const char * data ) { xcdCompressionError error; VARIANT dataToCompress; VARIANT compressedData; VARIANT uncompressedData; SAFEARRAY * safeArray; char * safeArrayData; size_t length;
/* The VARIANT structure doesn't directly support 8-bit strings. We will have to supply the string as a byte array. We will not compress the terminating null character. */
// Compute the length of the string length = strlen( data );
// Create a one-dimensional array using the length (excluding the null character) safeArray = SafeArrayCreateVector( VT_I1, 0, length ); // Access the array data and copy the string to the array SafeArrayAccessData( safeArray, ( void ** ) &safeArrayData ); CopyMemory( safeArrayData, data, length ); SafeArrayUnaccessData( safeArray );
// Initialize the variants we will use VariantInit( &dataToCompress ); VariantInit( &compressedData ); VariantInit( &uncompressedData );
// Set the data type to an array of bytes dataToCompress.vt = VT_ARRAY | VT_I1; // Assign the safe array to the VARIANT. Responsability is transfered dataToCompress.parray = safeArray;
// Compress the data error = compression->Compress( &dataToCompress, &compressedData, VARIANT_TRUE );
// We no longer need the data to compress VariantClear( &dataToCompress );
if ( error != xceSuccess ) throw new _com_error( error );
/* compressedData now contains an array of bytes. This is not a string. It is the compressed data and is not in a specific form.
In this example, we will display each byte in the array as an hexadecimal value. In a real application, the data in the array could be saved in a file, sent to another computer, whatever. */
printf( "Begin compressed data:\n" ); PrintByteArrayVariant< unsigned char >( &compressedData ); printf( "\nEnd compressed data.\n\n" );
// Uncompress the data error = compression->Uncompress( &compressedData, &uncompressedData, VARIANT_TRUE );
// We no longer need the compressed data VariantClear( &compressedData );
if ( error != xceSuccess ) throw new _com_error( error );
printf( "Begin uncompressed data:\n" ); PrintVariantAsString( &uncompressedData ); printf( "\nEnd uncompressed data.\n\n" );
// Clear the uncompressed data VariantClear( &uncompressedData ); }
static void UnicodeStringExample( IXceedCompressionPtr & compression, const wchar_t * data ) { xcdCompressionError error; VARIANT dataToCompress; VARIANT compressedData; VARIANT uncompressedData; _bstr_t bstring;
/* The VARIANT structure doesn't support straight unicode strings. But it does support something close to it. Something called BSTR.
A BSTR, known as basic string or binary string, is a pointer to a wide character string used by Automation data manipulation functions.
We will use the COM _bstr_t helper class to build the BSTR out of the supplied unicode string. */
// Copy the supplied unicode string data to the BSTR object bstring = data;
// Initialize the variants we will use VariantInit( &dataToCompress ); VariantInit( &compressedData ); VariantInit( &uncompressedData );
// Set the data type to BSTR dataToCompress.vt = VT_BSTR; // Assign the safe array to the VARIANT. Responsability is transfered dataToCompress.bstrVal = bstring;
// Compress the data error = compression->Compress( &dataToCompress, &compressedData, VARIANT_TRUE );
// We no longer need the data to compress VariantClear( &dataToCompress );
if ( error != xceSuccess ) throw new _com_error( error );
/* compressedData now contains an array of bytes. This is not a string. It is the compressed data and is not in a specific form.
In this example, we will display each byte in the array as an hexadecimal value. In a real application, the data in the array could be saved in a file, sent to another computer, whatever. */
printf( "Begin compressed data:\n" ); PrintByteArrayVariant< unsigned char >( &compressedData ); printf( "\nEnd compressed data.\n\n" );
// Uncompress the data error = compression->Uncompress( &compressedData, &uncompressedData, VARIANT_TRUE );
// We no longer need the compressed data VariantClear( &compressedData );
if ( error != xceSuccess ) throw new _com_error( error );
printf( "Begin uncompressed data:\n" ); PrintVariantAsUnicodeString( &uncompressedData ); printf( "\nEnd uncompressed data.\n\n" );
// Clear the uncompressed data VariantClear( &uncompressedData ); }
static void RawDataExample( IXceedCompressionPtr & compression, unsigned long * data, int count ) { xcdCompressionError error; VARIANT dataToCompress; VARIANT compressedData; VARIANT uncompressedData; SAFEARRAY * safeArray; unsigned long * safeArrayData; size_t size;
/* Although the VARIANT structure supports 4 byte unsigned integers, the Compress function only accepts BSTR or byte arrays in its VARIANT source parameter. We will therefore have to supply the data as a byte array. */
// Compute the size in bytes of the supplied data size = count * sizeof( unsigned long );
// Create a one-dimensional array of unsigned bytes safeArray = SafeArrayCreateVector( VT_UI1, 0, size ); // Access the array data and copy the data to the array SafeArrayAccessData( safeArray, ( void ** ) &safeArrayData ); CopyMemory( safeArrayData, data, size ); SafeArrayUnaccessData( safeArray );
// Initialize the variants we will use VariantInit( &dataToCompress ); VariantInit( &compressedData ); VariantInit( &uncompressedData );
// Set the data type to an array of unsigned bytes dataToCompress.vt = VT_ARRAY | VT_UI1; // Assign the safe array to the VARIANT. Responsability is transfered dataToCompress.parray = safeArray;
// Compress the data error = compression->Compress( &dataToCompress, &compressedData, VARIANT_TRUE );
// We no longer need the data to compress VariantClear( &dataToCompress );
if ( error != xceSuccess ) throw new _com_error( error );
/* compressedData now contains an array of bytes. This is not a string. It is the compressed data and is not in a specific form.
In this example, we will display each byte in the array as an hexadecimal value. In a real application, the data in the array could be saved in a file, sent to another computer, whatever. */
printf( "Begin compressed data:\n" ); PrintByteArrayVariant< unsigned char >( &compressedData ); printf( "\nEnd compressed data.\n\n" );
// Uncompress the data error = compression->Uncompress( &compressedData, &uncompressedData, VARIANT_TRUE );
// We no longer need the compressed data VariantClear( &compressedData );
if ( error != xceSuccess ) throw new _com_error( error );
printf( "Begin uncompressed data:\n" ); PrintByteArrayVariant< unsigned long >( &uncompressedData ); printf( "\nEnd uncompressed data.\n\n" );
// Clear the uncompressed data VariantClear( &uncompressedData ); }
template< class DataType > static void PrintByteArrayVariant( VARIANT * variant ) { DataType * data; SAFEARRAY * arrayDescriptor; int i, count;
// Get the array descriptor from the variant arrayDescriptor = variant->parray;
// Gain access to the array data SafeArrayAccessData( arrayDescriptor, ( void ** ) &data );
// Get the number of elements in the first dimension of the array count = arrayDescriptor->rgsabound[ 0 ].cElements / sizeof( DataType );
int lineThreshold = 32 / sizeof( DataType ); int groupThreshold = 4 / sizeof( DataType ); char buffer[ 16 ];
sprintf( buffer, "%%0%dX", sizeof( DataType ) * 2 ); for( i = 0; i < count; i++ ) { // If we need to change line if( ( i % lineThreshold ) == 0 && i > 0 ) printf( "\n" );
// If we need to seperate a group of data if( ( i % groupThreshold ) == 0 ) printf( " " );
// Access the current index as we would a normal array printf( buffer, data[ i ] ); }
// Release access to the array data SafeArrayUnaccessData( arrayDescriptor ); }
static void PrintVariantAsString( VARIANT * variant ) { char * string; SAFEARRAY * arrayDescriptor; int i, count;
// Get the array descriptor from the variant arrayDescriptor = variant->parray;
// Gain access to the array data SafeArrayAccessData( arrayDescriptor, ( void ** ) &string );
// Get the number of elements in the first dimension of the array count = arrayDescriptor->rgsabound[ 0 ].cElements;
/* Since the uncompressed data doesn't contain the terminating null character we either have to print the string one character at a time knowing the lenght of the array. Or, we can copy the data to another buffer that has the size to contain the null character.
Here, we choose to print one character at a time. */ for( i = 0; i < count; i++ ) { // Print the current character printf( "%c", string[ i ] ); }
// Release access to the array data SafeArrayUnaccessData( arrayDescriptor ); }
static void PrintVariantAsUnicodeString( VARIANT * variant ) { HRESULT result;
/* We need to convert the variant type from whatever (usually byte array in our examples) to BSTR. We will show how this is done when no helper classes are used. The VariantChangeType function does this. We will attempt to make this conversion in place (meaning to replace the current data with the converted data. */
// Convert the variant data to a BSTR result = VariantChangeType( variant, variant, 0, VT_BSTR );
// If the conversion was successful if( result == S_OK ) { /* We will use the COM BSTR wrapper class to easily access the actual string. But we will NOT copy the string data */
// Wrap the BSTR without copying the data _bstr_t bString( variant->bstrVal, false );
// BSTR strings are unicode const wchar_t * actualString = bString;
// Print the unicode string wprintf( L"%s", actualString ); } }
int main( int argc, char * argv[] ) { CoInitialize( NULL );
try { char textData[] = "It's actually 607 small islands in the South Pacific. " "Interestingly, while its total land mass is only 270 square miles, " "it occupies more than a million square miles of the Pacific Ocean. " "Population is 127,000 and the U.S. Embassy is located in the state of " "Pohnpei and not, as many people believe, on the island of Yap.";
wchar_t unicodeTextData[] = L"You need to listen to me. You have to listen to me. I can't help you, unless you listen " L"to me! You can't send Christmas cards to everyone, you can't do it! Forget the " L"SPR, let's get the IMF loans like we said we were going to, listen to what I have to say " L"about Didion, and please, listen to me!";
unsigned long rawData[] = { 0xFEEEEEEE, 0x80018001, 0x00000000, 0xFFFFFFFF, 0x36FE0006 };
// Create the XceedCompression object IXceedCompressionPtr compression( CLSID_XceedCompression ); // License the object if( compression->License( _bstr_t( L"your license key" ) ) == VARIANT_FALSE ) { printf( "License() failed.\n" ); return 1; }
/* There are several ways to manipulate VARIANT data. In this example, we will try to show how VARIANT data is handled without 'magic' so we will use the VARIANT structure directly.
The COM helper class _variant_t encapsulates a VARIANT structure and provides useful methods to work with it.
In MFC, the COleVariant class also encapsulates the VARIANT structure.
All the operations done on VARIANTs in these examples can be seen as simple methods in the _variant_t or COleVariant classes.
In order to keep this example from becoming too heavy, we will use the COM helper class _bstr_t that provides a useful wrapper around the BSTR data type. */ // A compression/decompression example using a string as data StringExample( compression, textData );
// A compression/decompression example using a unicode string as data UnicodeStringExample( compression, unicodeTextData );
// A compression/decompression example using raw data RawDataExample( compression, rawData, sizeof( rawData ) / sizeof( unsigned long ) ); } catch( const _com_error& error ) { printf( "COM error %08x. %S\n", error.Error(), ( const char* ) error.Description() ); } catch( ... ) { printf( "Unexpected error\n" ); }
CoUninitialize(); return 0; }
|